using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using System.Xml.Serialization;
using System.Reflection;


namespace xboxssbeatemup
{
    /// <summary>
    /// This is a game component that implements IUpdateable.
    /// </summary>
    public class Editor : Microsoft.Xna.Framework.DrawableGameComponent
    {
        public bool isEditing = true;

        public System.Windows.Forms.ListBox eAddObjectLst;
        public System.Windows.Forms.Button eAddObjectBtn;
        public System.Windows.Forms.Button eSaveLevelBtn;
        public System.Windows.Forms.Button eLoadLevelBtn;
        public System.Windows.Forms.TextBox eLevelFilenameTxt;

        public SpriteFont eFontArial = null;
        String eMessage = "";
        public int eSelectedObject = 0;

        public bool stopKeyboardCommands = false;
        enum TransformMode
        {
            Position,
            Rotation,
            Scale
        }
        enum EditingMode
        {
            Object,
            Camera
        }
        TransformMode eTransformMode = TransformMode.Position;
        EditingMode eMode = EditingMode.Object;
        const float ePositionSpeed = 0.1f;
        const float eRotationSpeed = 0.01f;
        const float eScaleSpeed = 0.01f;
        const float eShiftMultiplier = 15.0f;
        Vector3 screenSpace;

        public KeyboardState keyboardState;
        public KeyboardState prevKeyboardState;
        public MouseState mouseState;
        public MouseState prevMouseState;

        public LevelData levelData;
        public EditableGameObject[] eCreatedObjects;
        public int eMaxNumCreatedObjects = 1000;
        public int eNumCreatedObjects = 0;
        public int eActualNumCreatedObjects = 0;
        bool selectAll = false;

        public EditorPanelEnemy editorPanelEnemy;

        public bool createObject = false;
        public Assembly assembly;

        Vector2[] linePoints;
        const float lineDist = 50.0f;
        float creationDist = 150.0f;

        CameraComponent camera;
        GameObject player;
        
        public Editor(Game game, CameraComponent cam, GameObject plyr)
            : base(game)
        {
            camera = cam;
            player = plyr;
            // TODO: Construct any child components here
        }

        /// <summary>
        /// Allows the game component to perform any initialization it needs to before starting
        /// to run.  This is where it can query for any required services and load content.
        /// </summary>
        public override void Initialize()
        {
            keyboardState = Keyboard.GetState();
            prevKeyboardState = keyboardState;
            mouseState = Mouse.GetState();
            prevMouseState = mouseState;

            assembly = Assembly.GetExecutingAssembly();
            eFontArial = this.Game.Content.Load<SpriteFont>("Fonts\\Arial");

            levelData = new LevelData();

            
            linePoints = new Vector2[4];
            for (int i = 0; i < 4; i++)
            {
                linePoints[i] = Vector2.Zero;
            }

            editorPanelEnemy = new EditorPanelEnemy(this.Game);
            this.Game.Components.Add(editorPanelEnemy);
            editorPanelEnemy.top = 630;

            eAddObjectLst = new System.Windows.Forms.ListBox();
            System.Windows.Forms.Control.FromHandle(this.Game.Window.Handle).Controls.Add(eAddObjectLst);
            eAddObjectLst.Items.Add("Tree2");
            eAddObjectLst.Items.Add("Tree9");
            eAddObjectLst.Items.Add("MissileEnemy");
            eAddObjectLst.Left = 20;
            eAddObjectLst.Top = 24;
            eAddObjectLst.Width = 150;
            eAddObjectLst.SelectedValueChanged += new EventHandler(eAddObjectLst_SelectedValueChanged);

            eAddObjectBtn = new System.Windows.Forms.Button();
            System.Windows.Forms.Control.FromHandle(this.Game.Window.Handle).Controls.Add(eAddObjectBtn);
            eAddObjectBtn.Text = "Create New ...";
            eAddObjectBtn.Enabled = false;
            eAddObjectBtn.Left = 20;
            eAddObjectBtn.Top = 124;
            eAddObjectBtn.Width = 150;
            eAddObjectBtn.Click += new EventHandler(eAddObjectBtn_Click);

            eLoadLevelBtn = new System.Windows.Forms.Button();
            System.Windows.Forms.Control.FromHandle(this.Game.Window.Handle).Controls.Add(eLoadLevelBtn);
            eLoadLevelBtn.Text = "Load Level";
            eLoadLevelBtn.Left = this.Game.Window.ClientBounds.Width - 20 - 100;
            eLoadLevelBtn.Top = 5;
            eLoadLevelBtn.Width = 100;
            eLoadLevelBtn.Click += new EventHandler(eLoadLevelBtn_Click);

            eSaveLevelBtn = new System.Windows.Forms.Button();
            System.Windows.Forms.Control.FromHandle(this.Game.Window.Handle).Controls.Add(eSaveLevelBtn);
            eSaveLevelBtn.Text = "Save Level";
            eSaveLevelBtn.Left = this.Game.Window.ClientBounds.Width - 20 - 100;
            eSaveLevelBtn.Top = 30;
            eSaveLevelBtn.Width = 100;
            eSaveLevelBtn.Click += new EventHandler(eSaveLevelBtn_Click);

            eLevelFilenameTxt = new System.Windows.Forms.TextBox();
            System.Windows.Forms.Control.FromHandle(this.Game.Window.Handle).Controls.Add(eLevelFilenameTxt);
            eLevelFilenameTxt.Text = "Level01.level";
            eLevelFilenameTxt.Left = this.Game.Window.ClientBounds.Width - 20 - 100 - 5 - 120;
            eLevelFilenameTxt.Top = 5;
            eLevelFilenameTxt.Width = 120;
            eLevelFilenameTxt.Click += new EventHandler(eLevelFilenameTxt_Click);

            this.Game.IsMouseVisible = true;

            eCreatedObjects = new EditableGameObject[eMaxNumCreatedObjects];

            base.Initialize();

            LineBatch.Init(GraphicsDevice);
        }

        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {
            prevKeyboardState = keyboardState;
            keyboardState = Keyboard.GetState();
            prevMouseState = mouseState;
            mouseState = Mouse.GetState();

            if (isEditing)
            {
                eAddObjectBtn.Visible = true;
                eAddObjectLst.Visible = true;
                eLevelFilenameTxt.Visible = true;
                eLoadLevelBtn.Visible = true;
                eSaveLevelBtn.Visible = true;
            }
            else
            {
                eAddObjectBtn.Visible = false;
                eAddObjectLst.Visible = false;
                eLevelFilenameTxt.Visible = false;
                eLoadLevelBtn.Visible = false;
                eSaveLevelBtn.Visible = false;
            }

            if (eAddObjectLst.SelectedItem != null)
            {
                eAddObjectBtn.Text = "Create New " + eAddObjectLst.SelectedItem.ToString();
            }

            ProcessTextBoxInput(eLevelFilenameTxt, keyboardState, prevKeyboardState);
            ProcessTextBoxInput(editorPanelEnemy.healthTxt, keyboardState, prevKeyboardState);
            ProcessTextBoxInput(editorPanelEnemy.healthMaxTxt, keyboardState, prevKeyboardState);
            ProcessTextBoxInput(editorPanelEnemy.magicTxt, keyboardState, prevKeyboardState);
            ProcessTextBoxInput(editorPanelEnemy.magicMaxTxt, keyboardState, prevKeyboardState);
            ProcessTextBoxInput(editorPanelEnemy.experienceTxt, keyboardState, prevKeyboardState);
            ProcessTextBoxInput(editorPanelEnemy.goldTxt, keyboardState, prevKeyboardState);
            ProcessTextBoxInput(editorPanelEnemy.attackTxt, keyboardState, prevKeyboardState);
            ProcessTextBoxInput(editorPanelEnemy.defenseTxt, keyboardState, prevKeyboardState);
            ProcessTextBoxInput(editorPanelEnemy.speedTxt, keyboardState, prevKeyboardState);

            if (!stopKeyboardCommands)
                ProcessKeyboardCommands();


            foreach (EditableGameObject ego in eCreatedObjects)
            {
                if (ego != null && ego.alive)
                {
                    if (ego.editing)
                    {
                        //ego.rotation += new Vector3(0.015f, 0.02f, 0.03f);
                        //    ego.position = player.position;
                        Vector3 mousePos = new Vector3(mouseState.X, mouseState.Y, 0.0f);
                        ego.position = new Vector3(
                            camera.TopDownPosition.X + (mouseState.X - this.Game.Window.ClientBounds.Width / 2.0f) * -(player.position.Z - camera.TopDownPosition.Z) / this.Game.Window.ClientBounds.Width,
                            player.position.Y,
                            camera.TopDownPosition.Y - (mouseState.Y - this.Game.Window.ClientBounds.Height / 2.0f) * -(player.position.Z - camera.TopDownPosition.Z) / this.Game.Window.ClientBounds.Height);
                        ego.position = GraphicsDevice.Viewport.Unproject(
                            new Vector3(mousePos.X, mousePos.Y, 0.0f),
                            camera.Projection, camera.View,
                            Matrix.CreateWorld(new Vector3(0.0f, 0.0f, 0.0f), Vector3.Forward, Vector3.Up));
                        creationDist = camera.Position.Y - player.position.Y;
                        ego.position += Vector3.Multiply(Vector3.Normalize(ego.position - camera.TopDownPosition), creationDist);
                        // Set GameObject's height to terrain height
                        ego.position.Y = ((Game1)this.Game).heightMapInfo.GetHeight(ego.position);
                        if (mouseState.RightButton == ButtonState.Pressed && prevMouseState.RightButton == ButtonState.Released)
                        {
                            ego.editing = false;
                            ego.selected = false;
                            if (keyboardState.IsKeyDown(Keys.LeftShift) || keyboardState.IsKeyDown(Keys.RightShift))
                                createObject = true;
                        }
                    }

                }
            }

            if (createObject)
            {
                CreateNewObject();
                createObject = false;
            }
            stopKeyboardCommands = false;

            base.Update(gameTime);
        }

        /// <summary>
        /// Loads any component specific content
        /// </summary>
        protected override void LoadContent()
        {
            // TODO: Load any content

            base.LoadContent();
        }

        /// <summary>
        /// Allows the game component to draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Draw(GameTime gameTime)
        {
            foreach (EditableGameObject ego in eCreatedObjects)
            {
                if (ego != null && ego.alive)
                {
                    //DrawGameObject(ego);
                    ((Game1)this.Game).shader1.DrawGameObject(this.Game, camera, ego);
                    if (ego.selected)
                    {
                        DrawBoxAtPosition(ego.position, true);
                    }
                }
            }

            ((Game1)this.Game).spriteBatch.Begin();
            ((Game1)this.Game).spriteBatch.DrawString(eFontArial, eMessage, new Vector2(20, this.Game.Window.ClientBounds.Height - 200), Color.White, 0, Vector2.Zero, 1, SpriteEffects.None, 0.100f);
            if (isEditing)
            {
                ((Game1)this.Game).spriteBatch.DrawString(eFontArial, "Create new object:", new Vector2(20, 5), Color.White, 0, Vector2.Zero, 1, SpriteEffects.None, 0.100f);
            }
            editorPanelEnemy.DrawText(((Game1)this.Game).spriteBatch, eFontArial);
            ((Game1)this.Game).spriteBatch.End();

            base.Draw(gameTime);
        }

        void eLevelFilenameTxt_Click(object sender, EventArgs e)
        {
            // if (!eLevelFilenameTxt.Focused)
            //eLevelFilenameTxt.Text = "";
        }

        void eLoadLevelBtn_Click(object sender, EventArgs e)
        {
            LoadLevel(eLevelFilenameTxt.Text.ToString());
        }
        void eSaveLevelBtn_Click(object sender, EventArgs e)
        {
            SaveLevel(eLevelFilenameTxt.Text.ToString());
        }
        void eAddObjectLst_SelectedValueChanged(object sender, EventArgs e)
        {
            eAddObjectBtn.Enabled = true;
        }

        void eAddObjectBtn_Click(object sender, EventArgs e)
        {
            CreateNewObject();
        }

        void CreateNewObject()
        {
            if (eAddObjectLst.SelectedItem != null && eNumCreatedObjects < eMaxNumCreatedObjects)
            {
                eCreatedObjects[eNumCreatedObjects] = new EditableGameObject();
                eCreatedObjects[eNumCreatedObjects].alive = true;
                if (eAddObjectLst.SelectedItem.ToString() == "Tree2")
                {
                    eCreatedObjects[eNumCreatedObjects].model = this.Game.Content.Load<Model>("Models\\Terrain\\tree-2");
                    eCreatedObjects[eNumCreatedObjects].modelFilename = "Models\\Terrain\\tree-2";
                    Random rand = new Random();
                    eCreatedObjects[eNumCreatedObjects].modelRotation = new Vector3(-MathHelper.PiOver2, (float)rand.NextDouble() * 2 * MathHelper.Pi, 0.0f);
                    eCreatedObjects[eNumCreatedObjects].scale = (float)rand.NextDouble() + 4.0f;
                }
                if (eAddObjectLst.SelectedItem.ToString() == "Tree9")
                {
                    eCreatedObjects[eNumCreatedObjects].model = this.Game.Content.Load<Model>("Models\\Terrain\\tree9");
                    eCreatedObjects[eNumCreatedObjects].modelFilename = "Models\\Terrain\\tree9";
                }
                if (eAddObjectLst.SelectedItem.ToString() == "MissileEnemy")
                {
                    eCreatedObjects[eNumCreatedObjects] = new Enemy();
                    eCreatedObjects[eNumCreatedObjects].alive = true;
                    eCreatedObjects[eNumCreatedObjects].model = this.Game.Content.Load<Model>("Models\\Weapons\\missile");
                    eCreatedObjects[eNumCreatedObjects].modelFilename = "Models\\Weapons\\missile";
                }
                eCreatedObjects[eNumCreatedObjects].editing = true;
                // Deselect all other objects
                foreach (EditableGameObject ego in eCreatedObjects)
                {
                    if (ego != null && ego.alive)
                        ego.selected = false;
                }
                editorPanelEnemy.Hide();
                if (eCreatedObjects[eNumCreatedObjects].GetType().ToString() == "xboxssbeatemup.Enemy")
                    editorPanelEnemy.Show();
                eCreatedObjects[eNumCreatedObjects].selected = true;
                eCreatedObjects[eNumCreatedObjects].position = player.position;
                eSelectedObject = eNumCreatedObjects;
                eNumCreatedObjects++;
                eActualNumCreatedObjects++;
            }
        }

        void SaveLevel(String filename)
        {
            eActualNumCreatedObjects = 0;
            foreach (EditableGameObject ego in eCreatedObjects)
            {
                if (ego != null && ego.alive)
                {
                    eActualNumCreatedObjects++;
                }
            }
            levelData.SetSize(eActualNumCreatedObjects);
            int objectCounter = 0;
            foreach (EditableGameObject ego in eCreatedObjects)
            {
                if (ego != null && ego.alive)
                {
                    //levelData.objectTypes[objectCounter] = ego.GetType();
                    levelData.objectPositions[objectCounter] = ego.position;
                    levelData.objectRotations[objectCounter] = ego.rotation;
                    levelData.objectScales[objectCounter] = ego.scale;
                    levelData.objectModelFilenames[objectCounter] = ego.modelFilename;
                    levelData.objectModelPositions[objectCounter] = ego.modelPosition;
                    levelData.objectModelRotations[objectCounter] = ego.modelRotation;
                    levelData.objectTypes[objectCounter] = ego.GetType().ToString();
                    if (ego.GetType().ToString() == "xboxssbeatemup.Enemy")
                    {
                        levelData.initialStates[objectCounter] = ((Enemy)ego).initialState;
                        levelData.attackTriggers[objectCounter] = ((Enemy)ego).attackTrigger;
                        levelData.stats[objectCounter] = ((Enemy)ego).stats;
                    }
                    objectCounter++;
                }
            }

            FileStream stream = File.Open(Path.Combine(this.Game.Content.RootDirectory, "LevelData\\" + filename), FileMode.Create);
            XmlSerializer serializer = new XmlSerializer(typeof(LevelData));
            serializer.Serialize(stream, levelData);
            stream.Close();
        }

        void LoadLevel(String filename)
        {
            FileStream stream = File.Open(Path.Combine(this.Game.Content.RootDirectory, "LevelData\\" + filename), FileMode.Open, FileAccess.Read);
            XmlSerializer serializer = new XmlSerializer(typeof(LevelData));
            levelData = (LevelData)serializer.Deserialize(stream);
            stream.Close();

            eNumCreatedObjects = 0;
            eActualNumCreatedObjects = 0;
            eCreatedObjects = new EditableGameObject[eMaxNumCreatedObjects];
            for (int i = 0; i < levelData.numObjects; i++)
            {
                Type objectType = assembly.GetType(levelData.objectTypes[i]);
                eCreatedObjects[i] = (EditableGameObject)Activator.CreateInstance(objectType);
                eCreatedObjects[i].alive = true;
                eCreatedObjects[i].model = this.Game.Content.Load<Model>(levelData.objectModelFilenames[i]);
                eCreatedObjects[i].modelFilename = levelData.objectModelFilenames[i];
                eCreatedObjects[i].editing = false;
                eCreatedObjects[i].selected = false;
                eCreatedObjects[i].position = levelData.objectPositions[i];
                eCreatedObjects[i].rotation = levelData.objectRotations[i];
                eCreatedObjects[i].scale = levelData.objectScales[i];
                eCreatedObjects[i].modelPosition = levelData.objectModelPositions[i];
                eCreatedObjects[i].modelRotation = levelData.objectModelRotations[i];
                if (objectType.ToString() == "xboxssbeatemup.Enemy")
                {
                    ((Enemy)eCreatedObjects[i]).initialState = levelData.initialStates[i];
                    ((Enemy)eCreatedObjects[i]).attackTrigger = levelData.attackTriggers[i];
                    ((Enemy)eCreatedObjects[i]).stats = levelData.stats[i];
                }
                eNumCreatedObjects++;
                eActualNumCreatedObjects++;
            }
        }

        public void ProcessTextBoxInput(System.Windows.Forms.TextBox tb, KeyboardState state, KeyboardState prevState)
        {
            // Process textbox input
            if (tb.Focused)
            {
                stopKeyboardCommands = true;
                foreach (Microsoft.Xna.Framework.Input.Keys a in state.GetPressedKeys())
                {
                    bool isNew = true;
                    foreach (Microsoft.Xna.Framework.Input.Keys b in prevState.GetPressedKeys())
                    {
                        if (a == b)
                            isNew = false;
                    }
                    if (isNew)
                    {
                        // Any key except Backspace, Shift
                        if (a != Keys.Back && a != Keys.LeftShift && a != Keys.RightShift)
                        {
                            if (a == Keys.D0)
                                tb.Text += "0";
                            else if (a == Keys.D1)
                                tb.Text += "1";
                            else if (a == Keys.D2)
                                tb.Text += "2";
                            else if (a == Keys.D3)
                                tb.Text += "3";
                            else if (a == Keys.D4)
                                tb.Text += "4";
                            else if (a == Keys.D5)
                                tb.Text += "5";
                            else if (a == Keys.D6)
                                tb.Text += "6";
                            else if (a == Keys.D7)
                                tb.Text += "7";
                            else if (a == Keys.D8)
                                tb.Text += "8";
                            else if (a == Keys.D9)
                                tb.Text += "9";
                            else if (a == Keys.OemPeriod)
                                tb.Text += ".";
                            else
                                tb.Text += a.ToString().ToLower();
                        }
                        if (a == Keys.Back && tb.Text.Length > 0)
                            tb.Text = tb.Text.Substring(0, tb.Text.Length - 1);
                    }
                }
            }
        }

        public void ProcessKeyboardCommands()
        {
            // 'Tab' scrolls through selected objects
            if (keyboardState.IsKeyDown(Keys.Tab) && prevKeyboardState.IsKeyUp(Keys.Tab))
            {
                bool passedZeroIndex = false;
                if (keyboardState.IsKeyDown(Keys.LeftShift)
                    || keyboardState.IsKeyDown(Keys.RightShift)) // Cycle through objects backwards
                {
                    do
                    {
                        if (eSelectedObject > 0)
                            eSelectedObject--;
                        else
                        {
                            eSelectedObject = eNumCreatedObjects - 1;
                            passedZeroIndex = true;
                        }
                    } while (!eCreatedObjects[eSelectedObject].alive
                        && !(passedZeroIndex && eSelectedObject == 0));
                }
                else // Cycle through objects forwards
                {
                    do
                    {
                        if (eSelectedObject < eNumCreatedObjects - 1)
                            eSelectedObject++;
                        else
                        {
                            eSelectedObject = 0;
                            passedZeroIndex = true;
                        }
                    } while (!eCreatedObjects[eSelectedObject].alive
                        && !(passedZeroIndex && eSelectedObject == eNumCreatedObjects - 1));
                }

                foreach (EditableGameObject ego in eCreatedObjects)
                {
                    if (ego != null && ego.alive)
                    {
                        if (ego.selected)
                        {
                            ego.selected = false;
                        }
                    }
                }
                if (eCreatedObjects[eSelectedObject] != null && eCreatedObjects[eSelectedObject].alive)
                {
                    eCreatedObjects[eSelectedObject].selected = true;
                    if (eCreatedObjects[eSelectedObject].GetType().ToString() == "xboxssbeatemup.Enemy")
                    {
                        editorPanelEnemy.Show();
                    }
                    else
                        editorPanelEnemy.Hide();
                }
            }

            // 'A' selects or deselects all objects
            if (keyboardState.IsKeyDown(Keys.A) && prevKeyboardState.IsKeyUp(Keys.A))
            {
                selectAll = !selectAll;
                bool areAllEnemy = true;
                editorPanelEnemy.Hide();
                foreach (EditableGameObject ego in eCreatedObjects)
                {
                    if (ego != null && ego.alive)
                    {
                        ego.selected = selectAll;
                        if (ego.GetType().ToString() != "xboxssbeatemup.Enemy")
                            areAllEnemy = false;
                    }
                }
                if (areAllEnemy && selectAll)
                    editorPanelEnemy.Show();
            }

            // 'V' changes View Mode
            if (keyboardState.IsKeyDown(Keys.V) && prevKeyboardState.IsKeyUp(Keys.V))
            {
                switch (camera.viewMode)
                {
                    case CameraComponent.ViewMode.TopDown:
                        isEditing = false;
                        editorPanelEnemy.Hide();
                        camera.viewMode = CameraComponent.ViewMode.Gameplay;
                        eMessage = "Now in Gameplay View Mode.";
                        break;
                    case CameraComponent.ViewMode.Gameplay:
                        isEditing = true;
                        if (eCreatedObjects[eSelectedObject] != null && eCreatedObjects[eSelectedObject].GetType().ToString() == "xboxssbeatemup.Enemy")
                            editorPanelEnemy.Show();
                        camera.viewMode = CameraComponent.ViewMode.TopDown;
                        camera.TopDownPosition.X = player.position.X;
                        camera.TopDownPosition.Z = player.position.Z;
                        eMessage = "Now in Top-down View Mode.";
                        break;
                }
            }

            // 'T' changes Transform Mode
            if (keyboardState.IsKeyDown(Keys.T) && prevKeyboardState.IsKeyUp(Keys.T))
            {
                switch (eTransformMode)
                {
                    case TransformMode.Position:
                        eTransformMode = TransformMode.Rotation;
                        eMessage = "Transform Mode changed to Rotation.";
                        break;
                    case TransformMode.Rotation:
                        eTransformMode = TransformMode.Scale;
                        eMessage = "Transform Mode changed to Scale.";
                        break;
                    case TransformMode.Scale:
                        eTransformMode = TransformMode.Position;
                        eMessage = "Transform Mode changed to Position.";
                        break;
                }
            }
            // 'P' changes Transform Mode to Position
            if (keyboardState.IsKeyDown(Keys.P) && prevKeyboardState.IsKeyUp(Keys.P))
            {
                eTransformMode = TransformMode.Position;
                eMessage = "Transform Mode changed to Position.";
            }
            // 'R' changes Transform Mode to Rotation
            if (keyboardState.IsKeyDown(Keys.R) && prevKeyboardState.IsKeyUp(Keys.R))
            {
                eTransformMode = TransformMode.Rotation;
                eMessage = "Transform Mode changed to Rotation.";
            }
            // 'S' changes Transform Mode to Scale
            if (keyboardState.IsKeyDown(Keys.S) && prevKeyboardState.IsKeyUp(Keys.S))
            {
                eTransformMode = TransformMode.Scale;
                eMessage = "Transform Mode changed to Scale.";
            }

            // 'Delete' removes GameObjects
            if (keyboardState.IsKeyDown(Keys.Delete) && prevKeyboardState.IsKeyUp(Keys.Delete))
            {
                foreach (EditableGameObject ego in eCreatedObjects)
                {
                    if (ego != null && ego.alive)
                    {
                        if (ego.selected)
                        {
                            ego.alive = false;
                            eActualNumCreatedObjects--;
                        }
                    }
                }
            }


            if (keyboardState.IsKeyDown(Keys.OemCloseBrackets))
                camera.cameraHeight++;
            if (keyboardState.IsKeyDown(Keys.OemOpenBrackets))
                camera.cameraHeight--;


            // Transform selected objects
            if (eMode == EditingMode.Object)
            {
                foreach (EditableGameObject ego in eCreatedObjects)
                {
                    if (ego != null && ego.alive)
                    {
                        if (ego.selected)
                        {
                            float shiftMultiplier = 1.0f;
                            if (keyboardState.IsKeyDown(Keys.LeftShift) || keyboardState.IsKeyDown(Keys.RightShift))
                                shiftMultiplier = eShiftMultiplier;
                            if (keyboardState.IsKeyDown(Keys.LeftControl) && keyboardState.IsKeyUp(Keys.LeftAlt))
                            {
                                if (camera.viewMode == CameraComponent.ViewMode.TopDown)
                                {
                                    if (keyboardState.IsKeyDown(Keys.Left))
                                        ego.position.X -= ePositionSpeed * shiftMultiplier;
                                    if (keyboardState.IsKeyDown(Keys.Right))
                                        ego.position.X += ePositionSpeed * shiftMultiplier;
                                    if (keyboardState.IsKeyDown(Keys.Up))
                                        ego.position.Z -= ePositionSpeed * shiftMultiplier;
                                    if (keyboardState.IsKeyDown(Keys.Down))
                                        ego.position.Z += ePositionSpeed * shiftMultiplier;
                                }
                                if (camera.viewMode == CameraComponent.ViewMode.Gameplay)
                                {
                                    if (keyboardState.IsKeyDown(Keys.Left))
                                        ego.position.X -= ePositionSpeed * shiftMultiplier;
                                    if (keyboardState.IsKeyDown(Keys.Right))
                                        ego.position.X += ePositionSpeed * shiftMultiplier;
                                    if (keyboardState.IsKeyDown(Keys.Up))
                                        ego.position.Y += ePositionSpeed * shiftMultiplier;
                                    if (keyboardState.IsKeyDown(Keys.Down))
                                        ego.position.Y -= ePositionSpeed * shiftMultiplier;
                                }
                            }
                            if (keyboardState.IsKeyDown(Keys.LeftAlt) && keyboardState.IsKeyUp(Keys.LeftControl))
                            {
                                if (camera.viewMode == CameraComponent.ViewMode.TopDown)
                                {
                                    if (keyboardState.IsKeyDown(Keys.Up))
                                        ego.rotation.X -= eRotationSpeed * shiftMultiplier;
                                    if (keyboardState.IsKeyDown(Keys.Down))
                                        ego.rotation.X += eRotationSpeed * shiftMultiplier;
                                    if (keyboardState.IsKeyDown(Keys.Right))
                                        ego.rotation.Z -= eRotationSpeed * shiftMultiplier;
                                    if (keyboardState.IsKeyDown(Keys.Left))
                                        ego.rotation.Z += eRotationSpeed * shiftMultiplier;
                                }
                                if (camera.viewMode == CameraComponent.ViewMode.Gameplay)
                                {
                                    if (keyboardState.IsKeyDown(Keys.Up))
                                        ego.rotation.X -= eRotationSpeed * shiftMultiplier;
                                    if (keyboardState.IsKeyDown(Keys.Down))
                                        ego.rotation.X += eRotationSpeed * shiftMultiplier;
                                    if (keyboardState.IsKeyDown(Keys.Right))
                                        ego.rotation.Y += eRotationSpeed * shiftMultiplier;
                                    if (keyboardState.IsKeyDown(Keys.Left))
                                        ego.rotation.Y -= eRotationSpeed * shiftMultiplier;
                                }
                                if (keyboardState.IsKeyDown(Keys.NumPad5))
                                    ego.rotation = Vector3.Zero;
                            }
                            if (keyboardState.IsKeyDown(Keys.LeftAlt) && keyboardState.IsKeyDown(Keys.LeftControl))
                            {
                                if (keyboardState.IsKeyDown(Keys.Down))
                                    ego.scale -= eScaleSpeed * shiftMultiplier;
                                if (keyboardState.IsKeyDown(Keys.Up))
                                    ego.scale += eScaleSpeed * shiftMultiplier;
                            }
                        }
                    }
                }
            }
        }

        void DrawBoxAtPosition(Vector3 pos, bool isShaded)
        {
            screenSpace = GraphicsDevice.Viewport.Project(Vector3.Zero, camera.Projection, camera.View,
                                                               Matrix.CreateTranslation(pos));
            linePoints[0] = new Vector2(screenSpace.X - lineDist, screenSpace.Y - lineDist);
            linePoints[1] = new Vector2(screenSpace.X - lineDist, screenSpace.Y + lineDist);
            linePoints[2] = new Vector2(screenSpace.X + lineDist, screenSpace.Y + lineDist);
            linePoints[3] = new Vector2(screenSpace.X + lineDist, screenSpace.Y - lineDist);

            ((Game1)this.Game).spriteBatch.Begin();
            for (int i = 0; i < 4; i++)
            {
                LineBatch.DrawLine(((Game1)this.Game).spriteBatch,
                    Color.White,
                    linePoints[i],
                    linePoints[(i == 3 ? 0 : i + 1)]);
            }
            ((Game1)this.Game).spriteBatch.End();

            // Fix RenderStates for 3d that get messed up by SpriteBatch
            GraphicsDevice.RenderState.DepthBufferEnable = true;
            GraphicsDevice.RenderState.AlphaBlendEnable = false;
            GraphicsDevice.RenderState.AlphaTestEnable = false;
            GraphicsDevice.SamplerStates[0].AddressU = TextureAddressMode.Wrap;
            GraphicsDevice.SamplerStates[0].AddressV = TextureAddressMode.Wrap;

            if (isShaded)
            {
                VertexPositionColor[] vertPosCol = new VertexPositionColor[4];
                vertPosCol[0] = new VertexPositionColor(new Vector3(pos.X - 10.0f, pos.Y, pos.Z - 10.0f), new Color(Color.Magenta, 0.5f));
                vertPosCol[1] = new VertexPositionColor(new Vector3(pos.X + 10.0f, pos.Y, pos.Z - 10.0f), new Color(Color.Magenta, 0.5f));
                vertPosCol[2] = new VertexPositionColor(new Vector3(pos.X + 10.0f, pos.Y, pos.Z + 10.0f), new Color(Color.Magenta, 0.5f));
                vertPosCol[3] = new VertexPositionColor(new Vector3(pos.X - 10.0f, pos.Y, pos.Z + 10.0f), new Color(Color.Magenta, 0.5f));

                BasicEffect effect = new BasicEffect(GraphicsDevice, null);
                effect.VertexColorEnabled = true;
                effect.World = Matrix.Identity;
                effect.Projection = camera.Projection;
                effect.View = camera.View;
                effect.Begin();

                foreach (EffectPass pass in effect.CurrentTechnique.Passes)
                {
                    pass.Begin();
                    GraphicsDevice.RenderState.AlphaBlendEnable = true;
                    GraphicsDevice.RenderState.SourceBlend = Blend.SourceAlpha;
                    GraphicsDevice.RenderState.DestinationBlend = Blend.InverseSourceAlpha;
                    GraphicsDevice.RenderState.FillMode = FillMode.Solid;
                    //GraphicsDevice.RenderState.CullMode = CullMode.None;
                    GraphicsDevice.DrawUserIndexedPrimitives<VertexPositionColor>(
                        PrimitiveType.TriangleStrip,
                        vertPosCol,
                        0,   // vertex buffer offset to add to each element of the index buffer
                        4,   // number of vertices to draw
                        new int[] { 0, 1, 3, 2 },
                        0,   // first index element to read
                        2    // number of primitives to draw
                    );
                    pass.End();
                }
                effect.End();
            }

        }
    }
}